﻿using System;

namespace UtilZ.Dotnet.Ex.Audio
{
    /// <summary>
    /// Wave辅助类
    /// </summary>
    unsafe public partial class WaveHelper
    {
        /********************************************************************************************************************
         * 
         * 标准WAV文件头是一个固定格式的结构，通常为44字节，用于描述音频文件的基本信息。以下是32位采样的WAV文件头的结构和字段含义
         * 
         *  偏移量（字节） 	 字段名称 	        字节数 	 描述 	
         *  0-3            	 Chunk ID 	        4      	 固定为“RIFF”，表示这是一个RIFF文件。 	
         *  4-7            	 Chunk Size 	    4      	 文件总大小减去8字节。 	
         *  8-11           	 Format   	        4      	 固定为“WAVE”，表示这是一个WAV文件。 	
         *  12-15          	 Subchunk1 ID 	    4      	 固定为“fmt ”，表示格式块。 	
         *  16-19          	 Subchunk1 Size 	4      	 格式块的大小，对于PCM编码通常为16。 	
         *  20-21          	 Audio Format 	    2      	 编码格式，1表示PCM。 	
         *  22-23          	 Num Channels 	    2      	 声道数，1表示单声道，2表示双声道。 	
         *  24-27          	 Sample Rate 	    4      	 采样率，例如44100Hz。 	
         *  28-31          	 Byte Rate 	        4      	 数据传输速率，计算公式为：采样率×声道数×采样位数/8。 	
         *  32-33          	 Block Align 	    2      	 数据块对齐单位，计算公式为：声道数×采样位数/8。 	
         *  34-35          	 Bits Per Sample 	2      	 每个采样点的位数，32表示32位采样。 	
         *  36-39          	 Subchunk2 ID 	    4      	 固定为“data”，表示音频数据块。 	
         *  40-43          	 Subchunk2 Size 	4      	 音频数据的总长度。 	
         * 
         * 
         * 需要注意的是，32位采样的WAV文件在“Bits Per Sample”字段中会设置为32[2]。
         * 
         * 
         ********************************************************************************************************************/


        /// <summary>
        /// 44字节文件头大小,适用于PCM编码
        /// </summary>
        private const int _WAVE_HEAD_SIZE = 44;

        /// <summary>
        /// 58字节文件头大小,适用于32位Pcm、A律、Mu律编码
        /// </summary>
        private const int _WAVE_HEAD_SIZE58 = 58;

        /// <summary>
        /// 90字节文件头大小,适用于ADPCM
        /// </summary>
        private const int _WAVE_HEAD_SIZE90 = 90;

        /// <summary>
        /// 90字节文件头大小,适用于CSVD
        /// </summary>
        private const int _WAVE_HEAD_SIZE0 = 0;


        /// <summary>
        /// 获取指定wav数据编码的文件头大小
        /// </summary>
        /// <param name="encoding">wav数据编码</param>
        /// <param name="hasFact">仅对IeeeFloat编码有效,是否存在fact数据块[true:存在;false:不存在]</param>
        /// <returns>文件头大小</returns>
        /// <exception cref="NotImplementedException">未实现的编码类型</exception>
        public static int GetWaveHeadSize(WaveEncoding encoding, bool hasFact = false)
        {
            switch (encoding)
            {
                case WaveEncoding.Pcm:
                    return _WAVE_HEAD_SIZE;
                case WaveEncoding.IeeeFloat:
                    if (hasFact)
                    {
                        return _WAVE_HEAD_SIZE58;
                    }
                    else
                    {
                        return _WAVE_HEAD_SIZE;
                    }
                case WaveEncoding.ALaw:
                case WaveEncoding.MuLaw:
                    return _WAVE_HEAD_SIZE58;
                case WaveEncoding.Adpcm:
                    return _WAVE_HEAD_SIZE90;
                case WaveEncoding.IbmCvsd:
                    return _WAVE_HEAD_SIZE0;
                default:
                    throw new NotImplementedException($"获取wav文件头大小未实现的wave数据编码类型\"{encoding.ToString()}\".");
            }
        }


        internal static short CaculateAdpcmBlockAlign(int sampleRate)
        {
            short blockAlign;
            //switch (sampleRate)
            //{
            //    case 8000:
            //    case 11025:
            //        blockAlign = 256;
            //        break;
            //    case 22050:
            //        blockAlign = 512;
            //        break;
            //    case 44100:
            //    default:
            //        blockAlign = 1024;
            //        break;
            //}
            if (sampleRate < 16000)
            {
                blockAlign = 256;
            }
            else if (sampleRate < 44100)
            {
                blockAlign = 512;
            }
            else
            {
                blockAlign = 1024;
            }
            return blockAlign;
        }

        internal static int CaculateAdpcmTrunkSize(int sampleRate, short blockAlign, short chs, short sampleBits, out short samplesPerBlock)
        {
            //[播放速度(传输速度)] 数据传输率,含义:播波形数据传输速率（每秒平均字节数,每秒所需播放字节数）
            samplesPerBlock = (short)((((blockAlign - (7 * chs)) * 8) / (sampleBits * chs)) + 2);
            return ((sampleRate * blockAlign) / samplesPerBlock);
        }


    }

}

